from logger import logger

class InterconnectError(Exception):
    """
    handling class for interconnect exceptions
    """
    
    def __init__(self, culprit, value):
        """
        initialize the class
        """
        logger.error("interconnect: %s: %s" % (culprit, value))

class Interconnect:
    """
    A network of busses and associated utility functions to facilitate 
    inter-element and inter-cell data exchange. An interconnect object overlays
    an element or cell array.
    """
    
    def __init__(self, width = 4, height = 4):
        """
        start by defining a network of busses that will hold data
        """
        
        self.network = []
        
        for i in range(2*height + 1):
            self.network.append(['0'] * (2*width + 1))
    
    def find_entry(self, row, col, bus):
        """
        translate a cell or element array index to a network address
        """
        
        #convert to network indexes
        network_col = 2*col + 1
        network_row = 2*row + 1
        
        #offsets for between-row entries
        if bus in ['nw', 'n', 'ne']:
            network_row -= 1
        elif bus in ['sw', 's', 'se']:
            network_row += 1
        
        #offsets for between-column entries
        if bus in ['nw', 'w', 'sw']:
            network_col -= 1
        elif bus in ['ne', 'e', 'se']:
            network_col += 1

        if bus not in ['nw', 'n', 'ne', 'e', 'se', 's', 'sw', 'w', 'ab']:
            raise InterconnectError('bad bus name', bus)
        
        return (network_row, network_col)
    
    def set(self, row, col, bus, value):
        """
        assign a given value to the correct bus in the network
        """
        
        #find the network entry
        (i, j) = self.find_entry(row, col, bus)
        
        #assign the value to that bus
        try:
            self.network[i][j] = value
        except:
            raise InterconnectError('row/col out of range', (i, j))

    def get(self, row, col, bus):
        """
        return the bus value from a particular bus in the network
        """
         
        #find the network entry
        (i, j) = self.find_entry(row, col, bus)
        
        #return the value being held by that bus
        try:
            return self.network[i][j]
        except:
            raise InterconnectError('row/col out of range', (i, j))